package com.navinfo.platform.trip.common.arithmetic;

import com.navinfo.platform.trip.common.arithmetic.annotation.Arithmetic;
import com.navinfo.platform.trip.common.arithmetic.data.CommonData;
import com.navinfo.platform.trip.common.arithmetic.data.OuterStatisticData;
import com.navinfo.platform.trip.common.arithmetic.var.VarSharpAcceleration;
import com.navinfo.platform.trip.common.arithmetic.enums.EventStatus;
import com.navinfo.platform.trip.common.arithmetic.enums.EventType;
import com.navinfo.platform.trip.common.arithmetic.exception.RangeAssert;
import com.navinfo.platform.trip.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.platform.trip.common.config.ConfigMap;
import com.navinfo.platform.trip.common.util.ArithmeticUtils;
import com.navinfo.platform.trip.common.util.BigDecimalUtils;

import java.util.Optional;

/**
 * 激烈加速(急加速)算法.<br/>
 * 依赖{@link Mileage}里程油耗算法<br/>
 * 输出：统计、事件<br/>
 */
@Arithmetic(name = "激烈加速(急加速)算法")
public class SharpAcceleration extends AbstractArithmetic<VarSharpAcceleration> {
    /**
     * 算法名称
     */
    private final String arithmeticName = "激烈加速（急加速）";
    /**
     * 事件类型
     */
    private final EventType EVENT_TYPE = EventType.sharpAcceleration;

    /**
     * 速度阀值，km/h
     */
    private static final int BORDER_01 = 0;
    private static final int BORDER_02 = 30;
    private static final int BORDER_03 = 60;
    /**
     * 加速度阀值，m/平方s
     */
    private static final double ACC_THRESHOLD_01 =  ConfigMap.getDouble("H_Acc_Threshold_Speed_0_30");
    private static final double ACC_THRESHOLD_02 =  ConfigMap.getDouble("H_Acc_Threshold_Speed_30_60");
    private static final double ACC_THRESHOLD_03 = ConfigMap.getDouble("H_Acc_Threshold_Speed_60_");
    /**
     * 油门踏板开度阀值
     */
    private static final double throtThreshold  = ConfigMap.getDouble("Throt_Threshold");

    /**
     * 是否激烈加速
     */
    private boolean isSharpUp() {
        CommonData commonData = getCommonData();
        int speedKmh = commonData.getSpeedKmh();

        double accThreshold = 0.0;
        if (speedKmh >= BORDER_01 && speedKmh <= BORDER_02) {
            accThreshold = ACC_THRESHOLD_01;
        } else if (speedKmh > BORDER_02 && speedKmh <= BORDER_03) {
            accThreshold = ACC_THRESHOLD_02;
        } else if (speedKmh > BORDER_03) {
            accThreshold = ACC_THRESHOLD_03;
        }

        //进制转换
        accThreshold = BigDecimalUtils.divide(accThreshold * 1000, 3600, 2).doubleValue();

        //加速度大于阀值 并且 速度大于0 并且 油门踏板位置（目前取得油门开合度）大于阀值
        return commonData.getAcceleration()>accThreshold && commonData.getSpeedMs().intValue()>0 && commonData.getAcceleratorPosition()>throtThreshold;
    }
    @Override
    public void calculate() {
        logger.debug("{}算法开始...", arithmeticName);

        //1.油门开合度有效性验证
        RangeAssert.acceleratorIsInTheRange(getCommonData().getAcceleratorPosition());

        VarSharpAcceleration var = super.getObj();
        boolean curIsSharpUpSpeed = isSharpUp();
        boolean preIsSharpUpSpeed = var.isPreSharpUpSpeed();
        logger.debug("{}算法，急加速状态：pre:{},current:{}.", arithmeticName, preIsSharpUpSpeed, curIsSharpUpSpeed);

        //上一次或本次激烈加速，进入算法
        if (preIsSharpUpSpeed || curIsSharpUpSpeed) {
            EventStatus eventStatus = super.getEventStatus(preIsSharpUpSpeed, curIsSharpUpSpeed);
            if (EventStatus.START.equals(eventStatus)) {
                logger.debug("{}算法，事件开始.", arithmeticName);
                startEventData(EVENT_TYPE);
            } else if (EventStatus.IN.equals(eventStatus)) {
                logger.debug("{}算法，事件中.", arithmeticName);
                calcEventData(EVENT_TYPE);
            } else if (EventStatus.END.equals(eventStatus)) {
                logger.debug("{}算法，事件结束...", arithmeticName);
                calcEventData(EVENT_TYPE);
                endEventData(var);
            }
        }

        //行程结束时要清理对应的未结束事件
        if (getCommonData().isTripLastNode()) {
            endEventData(var);
        }

        //设置上一个点状态、供下个点计算
        var.setPreSharpUpSpeed(curIsSharpUpSpeed);
        logger.debug("{}算法结束...", arithmeticName);
    }

    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        VarSharpAcceleration varSharpAcceleration = super.getObj();
        statisticDataOut.setSharpUpSpeedMileage(ArithmeticUtils.mileageMToM(varSharpAcceleration.getMileage()));
        statisticDataOut.setSharpUpSpeedFuel(ArithmeticUtils.fuelMlToMl(varSharpAcceleration.getFuel()));
        statisticDataOut.setSharpUpSpeedDuration(ArithmeticUtils.timeMsToSecond(varSharpAcceleration.getDuration()));
        statisticDataOut.setSharpUpSpeedNumber(varSharpAcceleration.getNumber());
    }

    private void endEventData(VarSharpAcceleration var ){
        endEventData(EVENT_TYPE, eventData -> {
            var.addNumber(1 );
            var.addMileage( Optional.ofNullable(eventData.getExtendField05()).orElse(0.0));
            var.addFuel( Optional.ofNullable(eventData.getExtendField06()).orElse(0.0).intValue());
            var.addDuration( Optional.ofNullable(eventData.getDuration()).orElse(0L).intValue());
        });
    }

}
